package com.aizuda.boot.modules.business.log.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.text.csv.CsvWriter;
import cn.hutool.core.util.StrUtil;
import com.aizuda.boot.modules.business.log.annotation.Logging;
import com.aizuda.boot.modules.common.constant.enums.LogTypeEnum;
import com.aizuda.boot.modules.file.util.FileResponseUtil;
import com.aizuda.boot.modules.system.mapper.SysUserMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.aizuda.boot.modules.business.permission.domain.response.EmployeeShowVO;
import com.aizuda.boot.modules.business.log.domain.entity.OperationLogEntity;
import com.aizuda.boot.modules.business.log.domain.request.ExportLogDTO;
import com.aizuda.boot.modules.business.log.domain.request.LogQueryDTO;
import com.aizuda.boot.modules.business.log.domain.request.LogSaveDTO;
import com.aizuda.boot.modules.business.log.domain.response.LogShowDTO;
import com.aizuda.boot.modules.business.log.domain.response.LogExportDTO;
import com.aizuda.boot.modules.business.log.mapper.LogMapper;
import com.aizuda.boot.modules.business.log.service.LogService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author sangyirong
 * @ClassName LogServiceImpl
 * @Version 1.0
 * @Date 2025/6/5 19:39
 */
@Service
@Slf4j
public class LogServiceImpl extends ServiceImpl<LogMapper, OperationLogEntity> implements LogService {

    @Resource
    private LogMapper logMapper;
    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    public IPage<OperationLogEntity> getLogPage(IPage page, LogQueryDTO logQueryDTO) {
        return logMapper.getLogPage(page, logQueryDTO);
    }

    /**
     * 获取日志类型
     *
     * @return
     */
    @Override
    public List<HashMap<String, String>> getLogType() {
        LogTypeEnum[] values = LogTypeEnum.values();
        return Arrays.stream(values).map(type -> {
            HashMap<String, String> hashMap = new HashMap<>();
            hashMap.put("key", type.getCode());
            hashMap.put("value", type.getMsg());
            return hashMap;
        }).collect(Collectors.toList());
    }

    /**
     * 获取日志（分页查询）
     *
     * @param logQueryDTO
     * @return
     */
    @Override
    public IPage<LogShowDTO> getLogPage(LogQueryDTO logQueryDTO) {
        IPage<OperationLogEntity> page = new Page<>(logQueryDTO.getPageNo(), logQueryDTO.getPageSize());
        IPage<OperationLogEntity> logPage = logMapper.getLogPage(page, logQueryDTO);
        IPage<LogShowDTO> logShowDTOIPage = new Page<>(logQueryDTO.getPageNo(), logQueryDTO.getPageSize());
        List<Long> ids = logPage.getRecords().stream().map(OperationLogEntity::getOperatorId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(ids)) {
            return logShowDTOIPage;
        }

        // 简化获取用户信息的逻辑，如果查询失败则抛出异常
        // 这里需要根据实际的用户服务接口进行调整
        Map<Long, EmployeeShowVO> employeeMap = getEmployeeMap(ids);

        List<LogShowDTO> collect = logPage.getRecords().stream().map(log -> {
            LogShowDTO logShowDTO = new LogShowDTO();
            BeanUtils.copyProperties(log, logShowDTO);
            logShowDTO.setOperator(employeeMap.get(log.getOperatorId()));
            return logShowDTO;
        }).collect(Collectors.toList());

        BeanUtils.copyProperties(logPage, logShowDTOIPage);
        logShowDTOIPage.setRecords(collect);
        return logShowDTOIPage;
    }

    /**
     * 获取员工信息映射
     *
     * @param ids 员工ID列表
     * @return 员工信息映射
     */
    private Map<Long, EmployeeShowVO> getEmployeeMap(List<Long> ids) {
        // 这里需要根据实际的员工服务接口进行实现
        return sysUserMapper.selectByIds(ids).stream().map(employee -> {
            EmployeeShowVO employeeShowVO = new EmployeeShowVO();
            employeeShowVO.setId(employee.getId());
            employeeShowVO.setName(employee.getNickName());
            employeeShowVO.setAvatar(employee.getAvatar());
            return employeeShowVO;
        }).collect(Collectors.toMap(EmployeeShowVO::getId, employeeShowVO -> employeeShowVO));
    }

    /**
     * 保存日志
     *
     * @param logSaveDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveLog(LogSaveDTO logSaveDTO) {
        OperationLogEntity operationLogEntity = new OperationLogEntity();
        BeanUtils.copyProperties(logSaveDTO, operationLogEntity);
        logMapper.insert(operationLogEntity);
    }

    /**
     * 导出日志
     *
     * @param exportLogDTO
     * @param response
     */
    @Override
    @Logging(logType = LogTypeEnum.OPERATION_LOG_DOWNLOAD)
    public void exportLog(ExportLogDTO exportLogDTO, HttpServletResponse response) {
        try {
            // 1. 查询日志数据
            List<LogExportDTO> logData = logMapper.exportLogData(exportLogDTO);
            
            // 2. 生成文件名
            String fileName = "operation_log_" + DateUtil.format(new Date(), "yyyyMMdd_HHmmss") + ".csv";
            
            // 3. 设置响应头
            FileResponseUtil.setDownloadFileHeader(response, fileName);
            
            // 4. 创建CSV写入器
            CsvWriter csvWriter = CsvUtil.getWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8));
            
            // 5. 写入CSV头部
            String[] headers = {
                "日志ID", "合同ID", "事件类型", "操作内容", "操作人ID", 
                "用户名", "昵称", "操作时间", "来源IP", "操作结果", "错误信息"
            };
            csvWriter.writeHeaderLine(headers);
            
            // 6. 写入数据
            if (!CollectionUtils.isEmpty(logData)) {
                for (LogExportDTO logExport : logData) {
                    String[] rowData = {
                        StrUtil.toString(logExport.getId()),
                        StrUtil.toString(logExport.getContractId()),
                        logExport.getEventType() != null ? logExport.getEventType().getCode() : "",
                        StrUtil.toString(logExport.getOperationContent()),
                        StrUtil.toString(logExport.getOperatorId()),
                        StrUtil.toString(logExport.getUsername()),
                        StrUtil.toString(logExport.getNickName()),
                        logExport.getOperationTime() != null ? DateUtil.formatDateTime(logExport.getOperationTime()) : "",
                        StrUtil.toString(logExport.getSourceIp()),
                        StrUtil.toString(logExport.getResult()),
                        StrUtil.toString(logExport.getErrorMessage())
                    };
                    csvWriter.writeLine(rowData);
                }
            }
            
            // 7. 关闭写入器
            IoUtil.close(csvWriter);
            
            log.info("导出日志成功，导出记录数: {}", logData.size());
            
        } catch (Exception e) {
            log.error("导出日志失败", e);
            throw new RuntimeException("导出日志失败: " + e.getMessage());
        }
    }
}
